

const TerserPlugin = require("terser-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin")
const webpack = require("webpack")
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const {resolve,join} = require('path'); // node内置核心模块，用来设置路径。
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

module.exports = {
  entry: './src/js/index.js',   // 入口文件
  output: { // 输出配置
    filename: 'js/[name].[contenthash:8].js',      // 输出文件名
    publicPath:"./",
    path: resolve(__dirname, 'dist'),   // 项目所有打包文件存放的文件夹，一般在 dist 文件夹
  },
  module: {
    rules: [

        // babel
        {
          test: /\.js$/,
          exclude: /node_modules/,
          include: resolve("src"),
          use: 'happypack/loader?id=babel-js'   //此处将之前配置的babel的一些预设什么的替换为happy/loader。id=js，因为happy也可以打包css,
        },
        // {
        //     test: /\.js$/,
        //     exclude: /node_modules/,
        //     use: {
        //       loader: "babel-loader",
        //       options: {
        //         presets: ['@babel/preset-env']
        //       }
        //     }
        // },

        // ts
        {
          test: /\.tsx?$/,
          exclude: /node_modules/,
          use: 'ts-loader'   //此处将之前配置的babel的一些预设什么的替换为happy/loader。id=js，因为happy也可以打包css,
        },

        // eslint
        {
          test: /\.js$/,  //只检测js文件
          exclude: /node_modules/,  //排除node_modules文件夹
          enforce: "pre",  //提前加载使用
          use: { //使用eslint-loader解析
            loader: "eslint-loader" 
          }
        },

        // css
        { 
          test: /\.css$/,
          use: [ 
            {
              loader:MiniCssExtractPlugin.loader,
              options:{
                publicPath:"../"
              }
            },
            'css-loader',
            'postcss-loader'
          ]
        },

        // scss
        {
          test: /\.scss$/,
          use: [
            {
              loader:MiniCssExtractPlugin.loader,
            },
            'css-loader',
            'postcss-loader',
            'sass-loader'
          ]
        },    
        
        // file
        {
          loader: 'file-loader',
          test: /\.(woff|woff2|eot|ttf|otf)$/,
          options: {
            outputPath: 'static/',
            // publicPath:"../",
            // publicPath:"../../../",
            // outputPath:"ee",
            name: '[hash:8].[ext]',
          },
        },

        // url
        {
          test: /\.(png|jpg|gif|svg)$/,
          use: [
            {
              loader: 'url-loader',
              options: {
                esModule: false, // 这里设置为false
                // publicPath:"../../images/",
                outputPath:"./images/",
                limit: 8 * 1024,  // 8kb大小以下的图片文件都用base64处理
                name: '[hash:8].[ext]'  // hash值为7位，ext自动补全文件扩展名
              },
            },
            //压缩图片要在file-loader之后使用
            {	
              loader:'image-webpack-loader',
                  options:{
                      bypassOnDebug: true
                  }
            },
            {
              loader: 'img-loader',
              options: {
                plugins: [
                  require('imagemin-gifsicle')({
                    interlaced: false
                  }),
                  require('imagemin-mozjpeg')({
                    progressive: true,
                    arithmetic: false
                  }),
                  require('imagemin-pngquant')({
                    floyd: 0.5,
                    speed: 2
                  }),
                  require('imagemin-svgo')({
                    plugins: [
                      { removeTitle: true },
                      { convertPathData: false }
                    ]
                  })
                ]
              }
            }
          ]
        },

        // html
        {
          test: /\.(html)$/,
          use: {
            loader: 'html-loader'
          }
        },

    ]
  },
  plugins: [

    new HappyPack({
      id: 'babel-js',
      use: [{     // 将js的具体规则放置在此处
        loader: 'babel-loader',
        options: {
          presets: [
            '@babel/preset-env',
          ]
        }
      }],
      //共享进程池
      threadPool: happyThreadPool,
      //允许 HappyPack 输出日志
      verbose: true,
    }),

    new HardSourceWebpackPlugin(), // <- 直接加入这行代码就行

    // new BundleAnalyzerPlugin(),
    new MiniCssExtractPlugin({
        filename: "css/[name].[contenthash:8].css",
        chunkFilename: "css/[name].[contenthash:8].css"
    }),
    new OptimizeCssAssetsPlugin({
      cssProcessorPluginOptions: {
        preset: ['default', { discardComments: { removeAll: true } }],
      },
    }),
    new HtmlWebpackPlugin({
      title: "main",      
      template: './src/index.html',
      cdn: {
        css:['https://cdn.bootcss.com/element-ui/2.8.2/theme-chalk/index.css'],
        js: [
          'https://cdn.bootcss.com/vue/2.6.10/vue.min.js',
          'https://cdn.bootcss.com/element-ui/2.8.2/index.js'
        ]
      },
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true,
      }
    }),
    new CleanWebpackPlugin(),
    // new webpack.HashedModuleIdsPlugin()
  ],
  optimization: {

    minimizer: [
        new TerserPlugin({
          sourceMap: true, // Must be set to true if using source-maps in production
          terserOptions: {
            compress: {
              drop_console: false,
            },
          },
        }),
    ],

    // 找到chunk中共享的模块,取出来生成单独的chunk
    splitChunks: {
      chunks: "initial",  // async表示抽取异步模块，all表示对所有模块生效，initial表示对同步模块生效
      cacheGroups: {
        vendors: {  // 抽离第三方插件
          test: /[\\/]node_modules[\\/]/,     // 指定是node_modules下的第三方包
          name: "vendors",
          priority: -10,                       // 抽取优先级,
        },
        
        common: { // 抽离自定义工具库
          name: "common",
          test: /[\\/]src[\\/]/,
         // minChunks: 2, // 表示模块被不同 entry 引用了多少次，才能分离生成新chunk
          minSize: 0,  // 将引用模块分离成新代码文件的最小体积
          priority: -20,
        }
      }
    },
    
    // 为 webpack 运行时代码创建单独的chunk，存的是异步模块的名字
    runtimeChunk:{
      name:'manifest'
    }
    /*
    runtimeChunk 设置为 true, webpack 就会把 chunk 文件名全部存到一个单独的 chunk 中，
    这样更新一个文件只会影响到它所在的 chunk 和 runtimeChunk，避免了引用这个 chunk 的文件也发生改变。
    */
    // runtimeChunk: true, 
  },   
  externals: {
    echart: 'echarts'
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
    alias:{
      "@":resolve(__dirname,"src"),
      "css":resolve(__dirname,"src/css")
    }
  },
  
  mode: 'production'   // 生产环境(二选一)
};
